/**
 * @file STL_Text.cpp
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief 
 * @version 0.1
 * @date 2020-09-15
 * 
 * @copyright Copyright Sci-Tech Laboratories (c) 2020
 * 
 */

#include "STL_Text.h"
#include <netinet/in.h> // htons, htonl, ntons, ntonl
#include <iostream>
#include <algorithm>
#include <string>
#include <stdarg.h> // va_start va_end

namespace STL
{
    std::string STL_Text::format(const char *format, ...)
    {
        char temp[1024 * 16] = {0};
        va_list args;
        va_start(args, format); //第二个参数是...之前的参数
        vsnprintf(temp, 1024 * 16 - 1, format, args);
        va_end(args);
        return std::string(temp);
    }

    std::string STL_Text::toUpperHex(std::string str, size_t offset, size_t max /* = 0*/)
    {
        std::string ret = "";
        char tempBuffer[4];
        for (std::size_t i = offset; i < str.length(); i++)
        {
            if (max > 0 && i - offset >= max)
                break;
            uint8_t temp = str.at(i);
            sprintf(tempBuffer, "%02X", temp);
            ret.append(std::string(tempBuffer));
        }
        return ret;
    }

    std::string STL_Text::toLowerHex(std::string str, size_t offset, size_t max /* = 0*/)
    {
        std::string ret = "";
        char tempBuffer[4];
        for (std::size_t i = offset; i < str.length(); i++)
        {
            if (max > 0 && i - offset >= max)
                break;
            uint8_t temp = str.at(i);
            sprintf(tempBuffer, "%02x", temp);
            ret.append(std::string(tempBuffer));
        }
        return ret;
    }

    std::string STL_Text::toHex(std::string str)
    {
        return toLowerHex(str, 0, 80);
    }

    std::string STL_Text::toHex(std::string str, size_t offset)
    {
        return toLowerHex(str, offset, 80);
    }

    /**
     * @brief 大端读取UInt16（即网络字节序）
     * 
     * @param buffer 
     * @param offset 
     * @return uint16_t 
     */
    uint16_t STL_Text::readUInt16BE(std::string buffer, size_t offset)
    {
        if (buffer.size() < offset + 2)
            return 0;
        uint16_t buf1 = buffer.at(offset) & 0xFF;
        uint16_t buf2 = buffer.at(offset + 1) & 0xFF;
        return (buf1 << 8) + buf2;
    }

    bool STL_Text::string_start_with(const std::string &str, std::string prefix)
    {
        return (str.compare(0, prefix.size(), prefix) == 0);
    }

    bool STL_Text::string_end_with(const std::string &str, std::string suffix)
    {
        if (str.size() < suffix.size())
            return false;
        return (str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0);
    }

    /**
     * @brief 小端读取UInt16
     * 
     * @param buffer 
     * @param offset 
     * @return uint16_t 
     */
    uint16_t STL_Text::readUInt16LE(std::string buffer, size_t offset)
    {
        if (buffer.size() < offset + 2)
            return 0;
        uint16_t buf1 = buffer.at(offset) & 0xFF;
        uint16_t buf2 = buffer.at(offset + 1) & 0xFF;
        return (buf2 << 8) + buf1;
    }

    std::string STL_Text::StringToHexString(std::string str)
    {
        std::string output;
        char temp[8];
        for (size_t i = 0; i < str.length(); ++i)
        {
            sprintf(temp, "%.2x", *(uint8_t *)(str.data() + i));
            output.append(temp, 2);
        }
        return output;
    }

    std::string STL_Text::HexStringtoString(std::string str)
    {
        std::string output;
        const char *pString = str.c_str();
        for (size_t i = 0; i < str.size(); i++)
        {
            if ((pString[i] >= '0' && pString[i] <= '9') || (pString[i] >= 'A' && pString[i] <= 'F') || (pString[i] >= 'a' && pString[i] <= 'f')) //属于0-9集合,返回是
            {
            }
            else
            {
                return "";
            }
        }
        for (size_t i = 0; i < str.length(); i += 2)
        {
            std::string str_temp = str.substr(i, 2);
            int temp = std::stoi(str_temp, nullptr, 16);
            output.append(1, temp);
        }
        return output;
    }

    std::string STL_Text::trim(std::string str, std::string pattern /* = " "*/)
    {
        while (1)
        {
            std::string::size_type pos = str.find(pattern, 0);
            if (pos == 0)
            {
                str = str.substr(pattern.size());
            }
            else
            {
                break;
            }
        }
        while (1)
        {
            std::string::size_type pos = str.find(pattern, str.size() - pattern.size());
            if (pos == str.size() - pattern.size())
            {
                str = str.substr(0, str.size() - pattern.size());
            }
            else
            {
                break;
            }
        }
        return str;
    }

    std::string STL_Text::strRemove(std::string str, char ch)
    {
        std::string return_str = "";
        int length = (int)(str.length());
        for (int i = 0; i < length; i++)
            if (str[i] != ch)
                return_str += str[i];
        return return_str;
    }

    std::vector<std::string> STL_Text::split(std::string str, std::string pattern)
    {
        std::string::size_type pos;
        std::vector<std::string> result;
        if (str.empty())
            return result;
        str += pattern;
        size_t size = str.size();

        for (size_t i = 0; i < size; i++)
        {
            pos = str.find(pattern, i);
            if (pos < size)
            {
                std::string s = str.substr(i, pos - i);
                result.push_back(s);
                i = (int)(pos + pattern.size() - 1);
            }
        }

        return result;
    }

    std::string STL_Text::uint16ToNetworkString(STL::uint16 value)
    {
        std::string ret = "";
        value = htons(value);
        ret.append(1, (value & 0xFF));
        ret.append(1, ((value >> 8) & 0xFF));
        return ret;
    }

    std::string STL_Text::uint32ToNetworkString(STL::uint32 value)
    {
        std::string ret = "";
        value = htonl(value);
        ret.append(1, (value & 0xFF));
        ret.append(1, ((value >> 8) & 0xFF));
        ret.append(1, ((value >> 16) & 0xFF));
        ret.append(1, ((value >> 24) & 0xFF));
        return ret;
    }

    STL::uint32 STL_Text::networkCharPointToUint32(char *buf, size_t offset)
    {
        std::string temp = std::string(buf + offset, 4);
        return networkStringPointToUint32(temp, 0);
    }

    STL::uint16 STL_Text::networkCharPointToUint16(char *buf, size_t offset)
    {
        std::string temp = std::string(buf + offset, 2);
        return networkStringPointToUint16(temp, 0);
    }

    STL::uint16 STL_Text::networkStringPointToUint16(std::string buf, size_t offset)
    {
        std::string subStr = buf.substr(offset, 4);
        STL::uint16 ret = *(STL::uint16 *)(subStr.data());
        ret = ntohs(ret);
        return ret;
    }

    STL::uint32 STL_Text::networkStringPointToUint32(std::string buf, size_t offset)
    {
        std::string subStr = buf.substr(offset, 4);
        STL::uint32 ret = *(STL::uint32 *)(subStr.data());
        ret = ntohl(ret);
        return ret;
    }

    std::string STL_Text::genNumberPassword(int len)
    {
        std::string ret;
        if (len < 1)
            len = 8;
        //srand((int)time(NULL));
        for (int i = 0; i < len; i++)
        {
            int value = rand() % 10 + 0x30;
            ret.append(1, value);
        }
        return ret;
    };

    std::string STL_Text::genCharacterAndNumberPassword(int len)
    {
        std::string ret;
        if (len < 1)
            len = 8;
        //srand((int)time(NULL));
        for (int i = 0; i < len; i++)
        {
            int value = rand() % 62 + 0x30;
            if (value > 0x39)
                value += 7;
            if (value > 0x5A)
                value += 6;
            ret.append(1, value);
        }
        return ret;
    };

    std::string STL_Text::toUpperStr(std::string str)
    {
        transform(str.begin(), str.end(), str.begin(), ::toupper);
        return str;
    }

    std::string STL_Text::toLowerStr(std::string str)
    {
        transform(str.begin(), str.end(), str.begin(), ::tolower);
        return str;
    }

    bool STL_Text::stringCompareIgnoreCase(std::string str1, std::string str2)
    {
        return (toLowerStr(str1) == toLowerStr(str2));
    }

    std::string STL_Text::addZero(int len, std::string value)
    {
        return addChar(len, value, '0');
    }

    std::string STL_Text::addChar(int len, std::string value, char c)
    {
        std::string ret = "";
        if (value.size() >= len)
            return value;
        size_t addLen = len - value.size();
        ret.append(addLen, c);
        ret.append(value);
        return ret;
    }

    std::string STL_Text::string_format(const char *format, ...)
    {
#if 1 // 无长度限制
        va_list args;
        va_start(args, format);
        int count = vsnprintf(NULL, 0, format, args);
        va_end(args);

        va_start(args, format);
        char *buff = (char *)malloc((count + 1) * sizeof(char));
        vsnprintf(buff, (count + 1), format, args);
        va_end(args);

        std::string str(buff, count);
        free(buff);
        return str;

#else // 最大长度限制：1024 - 1
        char buff[1024] = {0};
        va_list args;
        va_start(args, format);
        vsnprintf(buff, sizeof(buff), format, args);
        va_end(args);

        std::string str(buff);
        return str;
        ;
#endif
    }

} // namespace STL
